# -*- coding: utf-8 -*-

"""
一个练习项目，用Python操作手机上的2048游戏
同时，结合一定的算法，看看能够达到的最大分

copyright: chysun2000@hotmail.com

算法模块，根据当前的状态，计算出下一步的操作
"""

from constant import SWIPE_LEFT, SWIPE_RIGHT, SWIPE_UP, SWIPE_DOWN, SWIPE_ERROR
from game import GameBoard, Square
from adb import AdbTool


class Algo:
    EMPTY_SCORE = 200
    MERGE_SCORE = 180
    MAX_SCORE = 10
    MONOTONICITY_SCORE = 100

    def __init__(self):
        self.depth_limit = 2
        self.possibility_2 = 0.9
        self.possibility_4 = 0.1

    @staticmethod
    def simulate_move(board, move):
        # print('simulate_move >>>')
        new_board = board.copy_new()
        new_board.move(move)
        return new_board

    @staticmethod
    def calculate_final_score(board):
        score = 0
        for row in range(GameBoard.ROW_COUNT):
            score += board.empty_cells_in_row(row) * Algo.EMPTY_SCORE
            score += board.merges_in_row(row) * Algo.MERGE_SCORE
            score += board.max_value_in_row(row) * Algo.MAX_SCORE
            score += board.monotonicity_in_row(row) * Algo.MONOTONICITY_SCORE

        for col in range(GameBoard.COL_COUNT):
            score += board.empty_cells_in_col(col) * Algo.EMPTY_SCORE
            score += board.merges_in_col(col) * Algo.MERGE_SCORE
            score += board.max_value_in_col(col) * Algo.MAX_SCORE
            score += board.monotonicity_in_col(col) * Algo.MONOTONICITY_SCORE

        return int(score)

    def calculate_move_score(self, board, current_depth, depth_limit):
        best_score = 0

        for move in [SWIPE_LEFT, SWIPE_RIGHT, SWIPE_UP, SWIPE_DOWN]:
            new_board = Algo.simulate_move(board, move)
            if not new_board.equals(board):
                score = self.generate_score(new_board, current_depth + 1, depth_limit)
                if best_score == 0:
                    best_score = score
                if score > best_score:
                    best_score = score

        return int(best_score)

    def generate_score(self, board, current_depth, depth_limit):
        # print('generate_score >>> current_depth =' + str(current_depth))
        if current_depth == depth_limit:
            # print('generate_score >>> reach depth_limit')
            return self.calculate_final_score(board)
        else:
            total_score = 0
            empty_squares = board.get_empty_squares()

            for square in empty_squares:
                new_board_2 = board.copy_new()
                new_board_2.set_square_value(square, Square.SQUARE_2)
                move_score_2 = self.calculate_move_score(new_board_2, current_depth, depth_limit)
                total_score = total_score + self.possibility_2 * move_score_2

                new_board_4 = board.copy_new()
                new_board_4.set_square_value(square, Square.SQUARE_4)
                move_score_4 = self.calculate_move_score(new_board_4, current_depth, depth_limit)
                total_score = total_score + self.possibility_4 * move_score_4

            return int(total_score)

    def calculate_score(self, board, move):
        new_board = Algo.simulate_move(board, move)
        if board.equals(new_board):
            return 0
        else:
            return self.generate_score(new_board, 0, self.depth_limit)

    def determine_next_move(self, board, last_operation):
        best_score = 0
        best_move = SWIPE_ERROR
        print('determine_next_move >>> BEGIN -----')
        print(board)
        scores = [0, 0, 0, 0]
        for move in [SWIPE_LEFT, SWIPE_RIGHT, SWIPE_UP, SWIPE_DOWN]:
            score = self.calculate_score(board, move)
            scores[move] = score
            if best_score == 0:
                best_score = score
                best_move = move
            elif score > best_score and score != 0:
                best_score = score
                best_move = move
            print('{ check move => ' + AdbTool.get_swipe_string(move) + ',\tScore = ' + str(score) + ' }')

        is_no_chance = True

        for score in scores:
            if score != 0:
                is_no_chance = False

        if is_no_chance:
            best_move = SWIPE_ERROR
            print('**** GAME OVER **** ')
        else:
            print('---------------------------------------------')
            print('{ Choose Move = ' + AdbTool.get_swipe_string(best_move) + ',\tScore = ' + str(best_score) + ' }')
            print('---------------------------------------------')
        print('determine_next_move >>> END -----')
        return best_move

    def adjust_limit(self, empty_cell_count):
        if empty_cell_count >= 10:
            self.depth_limit = 1
        elif 6 <= empty_cell_count < 10:
            self.depth_limit = 2
        else:
            self.depth_limit = 3
